package com.navinfo;

import com.navinfo.location.mileage.bean.MileageAndFuel;
import com.navinfo.location.mileage.bean.Point;
import com.navinfo.location.mileage.calculation.Calculation;
import com.navinfo.location.mileage.util.JsonUtil;
import com.navinfo.opentsp.platform.computing.analysis.entity.VehicleStatusAdditionDto;
import com.navinfo.opentsp.platform.computing.analysis.util.CommonUtil;
import com.navinfo.opentsp.platform.location.protocol.common.LCStatusType;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 读取hive导出的csv文件，计算里程油耗
 *
 * @author Administrator
 * @date 2017-05-31
 * @modify
 */

public class OfflineAnalysisMileage {

    private static final Logger logger = LoggerFactory.getLogger(OfflineAnalysisMileage.class);

    private static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static final String YYYYMMDD = "yyyyMMddHHmmss";

    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd");
    /**
     * 两点间油量阀值
     */
    private static double oilThreshold = 0.0333d;
    /**
     * 两点间里程阀值
     */
    private static double milThreshold = 1d;
    /**
     * 两点间里程阀值(KM/s)
     */
    private double lowMilThreshold = 0.03d;
    /**
     * 两点间里程阀值(KM/s)
     */
    private double lowOilThreshold = 0.0333d;
    /**
     * 切分段的时间阈值(毫秒)
     */
    private static long slicePeriod = 300_000L;

    /**
     * 一天里程最大值
     */

    private static int milMax = 2000;
    /**
     * 一天油耗最大值
     */
    private static int oilMax = 900;

    public static void main(String[] args) {

        File file = new File(
                "D:\\精准里程油耗\\对比数据\\14710507418_20180920.csv");
        try (LineIterator it = FileUtils.lineIterator(file, "UTF-8")) {

            List<Long> tidList = new ArrayList<>();
            Map<Long, List<Point>> pointMap = new HashMap<>();
            List<Point> pointList = new ArrayList<>();

            int j = 0;
            while (it.hasNext()) {
                if (j == 0) {
                    //第一行不处理
                    it.nextLine();
                    j++;
                    continue;
                }
                String line = it.nextLine();

                //参数bean
                Point point = new Point();
                getPointInfo(line, point);
                tidList.add(point.getTid());
                if (j >= 2) {
                    Long preTid = tidList.get(j - 2);
                    if (preTid != point.getTid()) {
                        pointMap.put(preTid, pointList);
                        pointList = new ArrayList<>();
                        pointList.add(point);
                    }
                }
                j++;
                pointList.add(point);
                //最后一条数据
                if (!it.hasNext()) {
                    pointMap.put(point.getTid(), pointList);
                }
            }
            List<MileageAndFuel> result = countData(pointMap);
            //截取通信号
            String tid = StringUtils.substringBefore(file.getName(), "-");

            File directory = new File(OfflineAnalysisMileage.class.getProtectionDomain()
                    .getCodeSource()
                    .getLocation()
                    .toURI()
                    .getPath()).getParentFile();

            String s = new DateTime().toString(YYYYMMDD);
            File outFile = FileUtils.getFile(directory.getAbsolutePath() + "/" + tid + "-" + s + ".txt");
            logger.info(outFile.getAbsolutePath());

            String json = JsonUtil.toJson(new Result<List>(result));
            FileUtils.writeStringToFile(outFile, json, "utf-8");

            for (Map.Entry<Long, List<Point>> entry : pointMap.entrySet()) {
                List<Point> points = entry.getValue();
                try {
                    outFile = FileUtils.getFile(directory.getAbsolutePath() + "/" + tid + "-" + s + "-points.txt");
                    FileUtils.writeStringToFile(outFile, JsonUtil.toJson(points), "utf-8");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            logger.error("", e);
        }
    }

    /**
     * 解析位置数据获得需要的参数
     *
     * @param point 参数bean
     */
    private static void getPointInfo(String msg, Point point) {

        String csvSplitBy = ",(?=([^\"]*\"[^\"]*\")*[^\"]*$)";
        String[] split = msg.split(csvSplitBy);
        String tid = split[0];
        long status = StringUtils.isBlank(split[2]) ? 0 : Long.parseLong(split[2]);
        String gpsTime = split[10];
        String statusAddition = split[89].replace("\"\"","\"").
                replace("\"[","[").
                replace("]\"","]");
        long mileage = StringUtils.isBlank(split[11]) ? 0 : Long.parseLong(split[11]);
        //GPS里程
        BigDecimal bigDecimal =  BigDecimal.valueOf(mileage).divide(
                new BigDecimal("1000"), 2, BigDecimal.ROUND_HALF_UP);
        double gpsMileage = bigDecimal.doubleValue();
        //仪表里程
        double mileageDD = 0d;
        //can里程(ecu)
        double ecuMileage = 0d;
        // 积分里程
        double differentialMileage = 0d;
        //燃油总消耗
        double totalFuelConsumption = 0d;
        //积分油耗
        double integralFuelConsumption = 0d;

        int rotationInt = 0;
        if (StringUtils.isNotEmpty(statusAddition)) {
            List<VehicleStatusAdditionDto> statusAdditionDtos = VehicleStatusAdditionDto.parseToList(statusAddition);
            for (VehicleStatusAdditionDto dto : statusAdditionDtos) {
                if (Integer.parseInt(dto.getTypes()) == LCStatusType.StatusType.oilValue.getNumber()) {

                } else if (Integer.parseInt(dto.getTypes()) == LCStatusType.StatusType.rotation.getNumber()) {
                    //转速
                    rotationInt = new BigDecimal(dto.getStatusValue()).
                            divide(new BigDecimal("100"), 0, BigDecimal.ROUND_HALF_UP).intValue();
                } else if (Integer.parseInt(dto.getTypes()) == LCStatusType.StatusType.mileage.getNumber()) {
                    //can里程(ecu)
                    ecuMileage = (double) dto.getStatusValue() / 100;
                } else if (Integer.parseInt(dto.getTypes()) == LCStatusType.StatusType.mileageDD.getNumber()) {
                    //仪表里程
                    mileageDD = (double) dto.getStatusValue() / 100;
                } else if (Integer.parseInt(
                        dto.getTypes()) == LCStatusType.StatusType.differentialMileage.getNumber()) {
                    // 积分里程
                    differentialMileage = (double) dto.getStatusValue() / 100;
                } else if (Integer.parseInt(
                        dto.getTypes()) == LCStatusType.StatusType.totalFuelConsumption.getNumber()) {
                    //燃油总消耗
                    totalFuelConsumption = (double) dto.getStatusValue() / 100;
                } else if (Integer.parseInt(
                        dto.getTypes()) == LCStatusType.StatusType.integralFuelConsumption.getNumber()) {
                    //积分油耗
                    integralFuelConsumption = (double) dto.getStatusValue() / 100;
                }
            }
        }
        int acc = (int) CommonUtil.getToBinary(status, 0);
        point.setTid(Long.valueOf(tid));
        point.setRotation(rotationInt);
        point.setGpsDate(Long.parseLong(gpsTime)*1000L);
        point.setAcc(acc);
        point.setMeterMileage(mileageDD);
        point.setEcuMileage(ecuMileage);
        point.setGpsMileage(gpsMileage);
        point.setTotalFuelCons(totalFuelConsumption);
        point.setDiffFuelCons(integralFuelConsumption);
    }

    private static List<MileageAndFuel> countData(Map<Long, List<Point>> pointMap) {
        List<MileageAndFuel> result = new ArrayList<>();
        for (Map.Entry<Long, List<Point>> entry : pointMap.entrySet()) {
            List<Point> o2 = entry.getValue();
            result.add(Calculation.getStdMilAndFuel(o2));
        }
        return result;
    }
}
